/*
 * main.cpp
 *
 *  Created on: 2009-3-26
 *      Author: W. Wen Peng
 */

#include <stdio.h>
#include <stdlib.h>
//#include "SocketPlus/Listener.h"
#include "Proxy_Server.h"
#include "NAtHelper.h"
#include <queue>
#include "XPacket.h"
#include <signal.h>
#include <list>
#include <unistd.h>	//int getopt( int argc, char *const argv[], const char *optstring );
#include <getopt.h> //getopt_long( int argc, char *const argv[], const char *optstring， char * longOpts[], int * lonigIndex );
void signal_handler(int);
void sigsegv_handler(int);

using namespace std;
static list<nat_rule> Nat_Rules;

struct cmdargs {
	char * des_ip;
	char * src_ip;
	char * local_ip;
	char * dport;
	char * port;
};

static const struct option longOpts[] = {
		{ "des_ip", required_argument, NULL, 1 },
		{ "src_ip", required_argument, NULL, 2 },
		{ "dport", required_argument, NULL, 3 },
		{ "ip", required_argument, NULL, 4 },
		{ "port", required_argument, NULL, 5 }
};
static const char * shortOpts="h";

static struct cmdargs cmdline ={NULL,NULL,NULL,NULL,NULL};

void getcmd(struct cmdargs * args,int argc, char * argvs[]){
	int longIndex = 0;
	int opt = getopt_long(argc, argvs, shortOpts,longOpts,&longIndex);
	while( opt != -1){
		switch( opt ){
		case 1:
			args->des_ip = optarg;
			break;
		case 2:
			args->src_ip = optarg;
			break;
		case 3:
			args->dport = optarg;
			break;
		case 4:
			args->local_ip = optarg;
			break;
		case 5:
			args->port = optarg;
			break;
		default:
			printf("gw [--des_ip v] [--dport v] [--src_ip v] [--ip v ] [--port v]\n");
			exit(0);
			break;
		}
		opt = getopt_long(argc, argvs, shortOpts,longOpts,&longIndex);
	}
}

int main(int argc, char * args[]) {

	getcmd(&cmdline, argc, args);

	if (signal(SIGINT, signal_handler) == SIG_ERR) {
		printf("failt to register signal handler!\n");
		exit(0);
	}
	if (signal(SIGSEGV, sigsegv_handler) == SIG_ERR) {
		printf("failt to register signal handler!\n");
		exit(0);
	}

	nat_rule rule;
	rule.d_port = 80;
	rule.des_ip = "202.197.66.223";
	rule.src_ip = "202.197.66.223";
	//	rule.in_if	="eth0";
	rule.chain = "PREROUTING";
	if(cmdline.dport){
		rule.d_port = atol(cmdline.dport);
	}
	if(cmdline.des_ip){
		rule.des_ip = cmdline.des_ip;
	}
	if(cmdline.src_ip){
		rule.src_ip = cmdline.src_ip;
	}
	if(cmdline.port){
		rule.redirect = atol(cmdline.port);
	}

	rule.redirect = 5001; //the local port specified to redirect.where a listenner socket will be create.
	NAtHelper::getInstance().AddDNat(rule);
	Nat_Rules.push_back(rule);

	Proxy_Server proxy;
	proxy.Create(AF_INET, SOCK_STREAM, IPPROTO_TCP, true);

	if(cmdline.local_ip){
		proxy.SetLocalIp(cmdline.local_ip);
	}
	proxy.SetLocalPort(rule.redirect);
	proxy.SetServAddr(rule.des_ip);
	proxy.SetServPort(rule.d_port);
	proxy.SetReuseAddr();
	proxy.Bind();
	proxy.Listen();

	Epoller::GetInstace().RegisterHandler(proxy, ACCEPT_EVENT);
	Epoller::GetInstace().AddEvent(EPOLLET);
	Epoller::GetInstace().StartUp(1000);
	Epoller::GetInstace().UnRegisterHandler(proxy, ACCEPT_EVENT);

	return 0;
}
void signal_handler(int i) {
	printf("program exit!\n");
	while (!Nat_Rules.empty()) {
		nat_rule rule = Nat_Rules.front();
		NAtHelper::getInstance().DelDNAT(rule);
		Nat_Rules.pop_front();
		printf("delete nat rule!\n");
	}
	exit(0);
}
void sigsegv_handler(int i) {
	printf("can not  access :\n");
	while (!Nat_Rules.empty()) {
		nat_rule rule = Nat_Rules.front();
		NAtHelper::getInstance().DelDNAT(rule);
		Nat_Rules.pop_front();
		printf("delete nat rule!\n");
	}
	exit(0);
}

